import { Card, CardProxy, CardType } from "@/core/cardsystem/card"
import { Player } from "../player"
import { PhaseBaseWrapper, PhaseEnum } from "../phase"


interface DropCardOptions {
    showOnDesk: boolean
}

const defaultDropCardOptions: DropCardOptions = {
    showOnDesk: true
}


class UsingLimitedPhaseWrapper extends PhaseBaseWrapper {
    execute(player: Player): Promise<void> {
        player.handCardAreas.resetUsedRecord()
        return super.execute(player)
    }
}

class CardProxyPhaseWrapper extends PhaseBaseWrapper {
    endPhase(player: Player) {

        player.handCardAreas.clearCardProxy(this.currentPhase())

        return super.endPhase(player)
    }
}


export class HandCardAreas {

    owner: Player

    handCards: Card[]

    cardProxys: Map<string, CardProxy<Card>>

    /** 当前回合内使用过的牌 */
    cacheUsedCards: Card[]

    constructor(owner: Player) {
        this.owner = owner
        this.handCards = []
        this.cacheUsedCards = []
        this.cardProxys = new Map()
        this.initPhaseWrapper()
    }

    initPhaseWrapper() {
        const alltrunPhases = [PhaseEnum.BEGIN, PhaseEnum.JUDGE, PhaseEnum.DRAWING, PhaseEnum.USING, PhaseEnum.THROW, PhaseEnum.END]
        this.owner.phaseController.registerBasePhaseHandlerByType(PhaseEnum.USING, UsingLimitedPhaseWrapper)
        for(const phase of alltrunPhases) {
            this.owner.phaseController.registerBasePhaseHandlerByType(phase, CardProxyPhaseWrapper)
        }
        
    }

    resetUsedRecord() {
        this.cacheUsedCards = []
    }

    cacheUsedRecord(card: Card) {
        this.cacheUsedCards.push(card)
    }

    countUsedCard<T extends Card>(cardCls: CardType<T>): number {
        return this.cacheUsedCards.filter(t => t instanceof cardCls).length
    }

    hasCanuseCard<T extends Card>(cardCls: CardType<T>): boolean {
        return this.handCards.filter(c => c instanceof cardCls && c.canuse()).length > 0
    }


    hasHandCards(): boolean {
        return this.handCards.length > 0
    }

    peekHandCard(): Card {
        return this.handCards[0]
    }

    acquireHandCard(card: Card) {
        card.cardProperties.owner = this.owner
        this.handCards.push(card)
    }

    setHandCard(handCards: Card[]) {
        this.handCards = handCards
        for(const card of handCards) {
            card.cardProperties.owner = this.owner
        }
    }

    handCardCount(): number {
        return this.handCards.length
    }

    dropCard(card: Card, options=defaultDropCardOptions) {
        let index = 0
        for(const c of this.handCards) {
            if ( c.equals(card)) {
                // TODO
                if (this.owner.phaseController.currentPhase() == PhaseEnum.USING) {
                    this.cacheUsedRecord(card)
                }
                this.handCards.splice(index, 1)
                break
            }
            index++
        }
    }

    registerCardProxy<T extends Card> (p: CardProxy<T>) {
        this.cardProxys.set(p.name, p)
    }

    removeCardProxy<T extends Card> (p: CardProxy<T>) {
        this.cardProxys.delete(p.name)
    }

    hasCardProxy<T extends Card> (p: CardProxy<T>): boolean {
        return this.cardProxys.has(p.name)
    }

    clearCardProxy(phase: PhaseEnum) {
        for(const cp of this.cardProxys.values()) {
            if (cp.expirePhase() == phase) {
                this.removeCardProxy(cp)
            }
        }
    }

    getCardProxys(): CardProxy<Card>[] {
        const res: CardProxy<Card>[] = []
        for (const cp of this.cardProxys.values()) {
            res.push(cp)
        }
        return res
    }

    useCard(card: Card): Card {
        let targetCard = card
        for(const cp of this.cardProxys.values()) {
            if (cp.shouldApply(card)) {
                targetCard = cp.apply(targetCard)
            }
        }

        return targetCard
    }

    getHandCards(needProxy=false): Card[] {
        if (needProxy) {
            const res = []
            for(const card of this.handCards) {
                let proxyCard = card
                for(const cp of this.cardProxys.values()) {
                    if (cp.shouldApply(card)) {
                        proxyCard = cp.apply(proxyCard)
                    }
                }
                res.push(proxyCard)
            }
            return res
        } else {
            return this.handCards
        }
    }

    matchesHandCards<T extends Card>(cls: CardType<T>) : T[] {
        const handCards = this.handCards
        const res = []
        for(const card of handCards) {
            if (card instanceof cls) {
                res.push(card)
            }
        }
        return res
    }

}
